package f.h.dragon.luceneInAction.test;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import junit.framework.TestCase;
import static f.h.dragon.util.OutUtil.*;

import org.apache.log4j.Logger;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.Field.TermVector;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

import f.h.dragon.util.CloseableUtil;
import f.h.dragon.util.FileUtil;
import f.h.dragon.util.IStorage;
import f.h.dragon.util.Storage;

import static f.h.dragon.luceneInAction.test.RANSearchUserDatas.*;

/**
 * Tester: test utilities
 * 
 * @author Wenlong Meng(wenlong.meng@gmail.com)
 * @version 1.0 at 2012/02/05
 * @since 1.0
 */
public class RANSearchUserTester extends TestCase {
	
	//local variables
	/**
	 * logger
	 */
	private static Logger logger = Logger.getLogger(RANSearchUserTester.class);
	/**
	 * index searcher
	 */
	private static IndexSearcher is = null;
	/**
	 * index writer
	 */
	private static IndexWriter iw = null;
	/**
	 * path
	 */
	private String path = "/data/testSearch/testUsers";
	
	/**
	 * init...
	 * 
	 * @see junit.framework.TestCase#setUp()
	 */
	@Override
	protected void setUp() throws Exception {
		super.setUp();
		iw = getWriter(path);
		is = getSearcher(path);
	}
	
	/**
	 * destroy...
	 * @see junit.framework.TestCase#tearDown()
	 */
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		CloseableUtil.close(iw);
		CloseableUtil.close(is);
	}
	
	/**
	 * 多线程测试
	 */
	public static void testMutilSearchUsers(){
		int i = 10;
		while(i-- > 0){
			new Thread(new Runnable(){
				@Override
				public void run() {
					testSearchUsers();
				}
			}).start();
		}
		
	}
	
	/**
	 * 测试搜索用户
	 */
	public static void testSearchUsers(){
		long st = System.currentTimeMillis();
//		outln("Begin: make search users datas " + st);
//		QueryParser qp = new QueryParser(LUCENE_VERSION, "name", new StandardAnalyzer(LUCENE_VERSION));
//		qp.setDefaultOperator(Operator.AND);
		try {
//			Query query = new TermQuery(new Term("name", "鈴木明美"));
			BooleanQuery query = new BooleanQuery();
			query.add(new TermQuery(new Term("major_type", "2")), Occur.SHOULD);
			PhraseQuery query1 = new PhraseQuery();
			PhraseQuery query2 = new PhraseQuery();
			PhraseQuery query5 = new PhraseQuery();
			String[] cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
				query2.add(new Term("company_desc", _cn));
				
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
				query2.add(new Term("company_desc", _cn));
			}
			cn = JOBS[random.nextInt(10000) % JOBS.length].split("");
			for(String _cn : cn){
				query1.add(new Term("company_name", _cn));
				query2.add(new Term("company_desc", _cn));
				query5.add(new Term("desc", _cn));
				query5.add(new Term("english_desc", _cn));
			}
			query.add(query1, Occur.SHOULD);
			query.add(query2, Occur.SHOULD);
			PhraseQuery query3 = new PhraseQuery();
			PhraseQuery query4 = new PhraseQuery();
			String[] sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			sn = SCHOOLS[random.nextInt(10000) % SCHOOLS.length].split("");
			for(String _sn : sn){
				query3.add(new Term("school_name", _sn));
				query4.add(new Term("school_desc", _sn));
				query5.add(new Term("desc", _sn));
			}
			query.add(query3, Occur.SHOULD);
			query.add(query4, Occur.SHOULD);
			query.add(query5, Occur.SHOULD);
			
			outln(query);
			TopDocs _docs = is.search(query, 100);
			List<String> ids = new ArrayList<String>();
			for(ScoreDoc _doc : _docs.scoreDocs){
				Document doc = is.doc(_doc.doc);
				ids.add(doc.get("id"));
			}
			outln("total = " + _docs.totalHits);
//			outln(ids);
		} catch (Exception e) {
			logger.error(e);
		}
		long et = System.currentTimeMillis();
//		outln("End: make search users datas " + et);
		outln("cost: " + (et - st));
	}
	
	/**
	 * 获取 index searcher
	 * 
	 * @return
	 */
	public static IndexSearcher getSearcher(String path){
		try {
			IndexSearcher is = new IndexSearcher(FSDirectory.open(new File(path)));
			return is;
		} catch (Exception e) {
			logger.error(e);
		}
		return null;
	}
	
	/**
	 * 生成用户数据
	 * 
	 * @param doc
	 */
	public static void testMakeUserDatas(){
		long st = System.currentTimeMillis();
		outln("Begin: make index users datas " + st);
		int i = 1000000;
		try {
			while(i-- > 0){outln("doc:" + i);
				iw.addDocument(makeDoc(makeInfo()));
			}
		} catch (Exception e) {
			logger.error(e);
		}finally{
			try {
				iw.commit();
			} catch (Exception e) {
				logger.error(e);
			}
		}
		long et = System.currentTimeMillis();
		outln("End: make index users datas " + et);
		outln("cost: " + (et - st));
	}
	
	/**
	 * 生成Document
	 * 
	 * @param storage
	 * @return
	 */
	@SuppressWarnings({ "rawtypes" })
	public static Document makeDoc(IStorage storage){
		Document doc = new Document();
		Iterator itr = storage.iterator();
		while(itr.hasNext()){
			String name = (String)itr.next();
			Object o = storage.get(name);
			if(o instanceof Iterable){
				Iterator os = ((Iterable)o).iterator(); 
				while(os.hasNext()){
					Index index = INDEX_CONFIGS.get(name);
					Store store = STORE_CONFIGS.get(name);
					doc.add(new Field(name, String.valueOf(os.next()), store == null ? Store.NO : store, index == null ? Index.NOT_ANALYZED : index, TermVector.YES));
				}
			}else{
				Index index = INDEX_CONFIGS.get(name);
				Store store = STORE_CONFIGS.get(name);
				doc.add(new Field(name, String.valueOf(o), store == null ? Store.NO : store, index == null ? Index.NOT_ANALYZED : index, TermVector.YES));
			}
		}
		
		return doc;
	}
	
	/**
	 * 获取indexwriter
	 */
	public static IndexWriter getWriter(String dir){
		logger.debug("exec: getWriter(" + dir + ")...");
		try {
			IndexWriterConfig iwc = new IndexWriterConfig(LUCENE_VERSION,
					new StandardAnalyzer(LUCENE_VERSION));
			iwc.setOpenMode(OpenMode.CREATE);
			logger.debug(iwc);
			IndexWriter iw = new IndexWriter(FSDirectory.open(new File(dir)), iwc);
			logger.debug("IndexWriter:" + iw);
			return iw;
		} catch (IOException e) {
			logger.error(e);
		}
		return null;
	}
	
	/**
	 * 生成用户信息
	 * 
	 * @return
	 */
	public static IStorage makeInfo(){
		IStorage storage = Storage.malloc();
		//id
		storage.put("id", ++ID);
		//生成名称
		storage.put("name", makeName());
		storage.put("reg_cmpny_num", random.nextInt(11));//経験社数
		storage.put("po_snd_user_exc_f", random.nextInt(3));//オファー送信済み除外
		storage.put("school_type_id", random.nextInt(50) * 10000);//最終学歴CD
		storage.put("english_level", random.nextInt(10));//英語会話レベル
		storage.put("stage_radios_cd", random.nextInt(10));//就業状況
		//会社名
		List<String> company_name = Arrays.asList(makeJobs());
		if(company_name != null && !company_name.isEmpty()){
			storage.put("company_name", company_name);
			//会社概要
			List<String> company_desc = new ArrayList<String>();
			for(int i = 0, counti = company_name.size(); i < counti; i++){
				company_desc.add(random(JOBS) + random(FNS) + random(SCHOOLS) + random(SNS));
			}
			storage.put("company_desc", company_desc);
			//業種CD
			List<Integer> lower_industry_cd = new ArrayList<Integer>();
			for(int i = 0, counti = company_name.size(); i < counti; i++){
				lower_industry_cd.add(1 << random.nextInt(11));
			}
			storage.put("lower_industry_cd", lower_industry_cd);
			//職種CD
			List<Integer> lower_headline_cd = new ArrayList<Integer>();
			for(int i = 0, counti = company_name.size(); i < counti; i++){
				lower_headline_cd.add(1 << random.nextInt(11));
			}
			storage.put("lower_headline_cd", lower_headline_cd);
			//従業員数CD
			List<Integer> staff_count_cd = new ArrayList<Integer>();
			for(int i = 0, counti = company_name.size(); i < counti; i++){
				staff_count_cd.add(random.nextInt(20));
			}
			storage.put("staff_count_cd", staff_count_cd);
			//勤務地CD
			List<Integer> region_cd = new ArrayList<Integer>();
			for(int i = 0, counti = company_name.size(); i < counti; i++){
				region_cd.add(random.nextInt(50));
			}
			storage.put("region_cd", region_cd);
			//最終役職CD
			List<Integer> level_cd = new ArrayList<Integer>();
			for(int i = 0, counti = company_name.size(); i < counti; i++){
				level_cd.add(random.nextInt(50));
			}
			storage.put("level_cd", level_cd);
		}
		//学校名
		List<String> school_name = Arrays.asList(makeSchools());
		if(school_name != null && !school_name.isEmpty()){
			storage.put("school_name", school_name);
			//概要
			List<String> school_desc = new ArrayList<String>();
			for(int i = 0, counti = school_name.size(); i < counti; i++){
				school_desc.add("");
			}
			storage.put("school_desc", school_name);
			//保有資格
			List<String> retain_eligibility = new ArrayList<String>();
			for(int i = 0, counti = school_name.size(); i < counti; i++){
				retain_eligibility.add(random(JOBS) + random(FNS) + random(SCHOOLS) + random(SNS));
			}
			storage.put("retain_eligibility", retain_eligibility);
			//文理区分
			List<Integer> major_type = new ArrayList<Integer>();
			for(int i = 0, counti = school_name.size(); i < counti; i++){
				major_type.add(random.nextInt(3));
			}
			storage.put("major_type", major_type);
			//学部系統CD
			List<Integer> faculty_id = new ArrayList<Integer>();
			for(int i = 0, counti = school_name.size(); i < counti; i++){
				faculty_id.add(random.nextInt(50) * 10000);
			}
			storage.put("faculty_id", faculty_id);
		}
		storage.put("english_desc", random(JOBS) + random(FNS) + random(SCHOOLS) + random(SNS));//英語語学力コメント
		storage.put("english_practice_content", random(JOBS) + random(FNS) + random(SCHOOLS) + random(SNS));//実務内容（英語）
		storage.put("desc", random(JOBS) + random(FNS) + random(SCHOOLS) + random(SNS));//自己紹介
		storage.put("expertise", random(JOBS) + random(FNS) + random(SCHOOLS) + random(SNS));//専門分野
		
		//log
		StringBuilder sb = new StringBuilder();
		String[] keys = {"id","name","company_name","reg_cmpny_num","po_snd_user_exc_f","school_type_id","english_level","stage_radios_cd","company_desc",
				"lower_industry_cd","lower_headline_cd","staff_count_cd","region_cd","level_cd","school_name","school_desc","retain_eligibility",
				"major_type","faculty_id","english_desc","english_practice_content","desc","expertise"};
		for(String key : keys){
			Object o = storage.get(key);
			if(o instanceof Iterable){
				@SuppressWarnings("rawtypes")
				Iterator os = ((Iterable)o).iterator(); 
				while(os.hasNext()){
					Object _o = os.next();
					if(_o != null){
						sb.append(String.valueOf(_o)).append(',');
					}
				}
			}else if( o != null){
				sb.append(String.valueOf(o)).append(',');
			}
		}
		
		FileUtil.appendln("/data/testSearch/users.fhdragon", sb.delete(sb.length() - 1, sb.length()).toString());
		
		return storage;
	}
	
	/**
	 * 随机获取一个字符串
	 * 
	 * @param s
	 * @return
	 */
	public static String random(String[] s){
		return s[random.nextInt(10000)%s.length];
	}

	/**
	 * 日本人名生成
	 * 
	 * @return
	 */
	public static String makeName() {
		return FNS[random.nextInt(10000) % FNS.length]
				+ SNS[random.nextInt(10000) % SNS.length];
	}

	/**
	 * 职历生成
	 * 
	 * @return
	 */
	public static String[] makeJobs() {
		int count = random.nextInt(5);
		String[] ss = new String[count];
		for(int i = 0; i < count; i++){
			ss[i] = JOBS[random.nextInt(10000) % JOBS.length];
		}
		return ss;
	}

	/**
	 * 职历生成
	 * 
	 * @return
	 */
	public static String[] makeSchools() {
		int count = random.nextInt(5);
		String[] ss = new String[count];
		for (int i = 0; i < count; i++) {
			ss[i] = SCHOOLS[random.nextInt(10000) % SCHOOLS.length];
		}
		return ss;
	}

	// local variables
	/**
	 * 随机函数
	 */
	public static Random random = new Random();
	/**
	 * 用户id
	 */
	public static int ID = 1000000;
	/**
	 * 测试用户数
	 */
	public static int COUNT = 1000000;
	/**
	 * lucene version
	 */
	public static final Version LUCENE_VERSION = Version.LUCENE_34;
	/**
	 * 索引数据路径
	 */
	public static String INDEX_DIR = "/data/testBizSearchUser";
	/**
	 * store config
	 */
	public static Map<String, Store> STORE_CONFIGS = new HashMap<String, Store>();
	static{
		STORE_CONFIGS.put("id", Store.YES);
	}
	/**
	 * index config
	 */
	public static Map<String, Index> INDEX_CONFIGS = new HashMap<String, Index>();
	static{
		INDEX_CONFIGS.put("id", Index.ANALYZED);
		INDEX_CONFIGS.put("company_name", Index.ANALYZED);
		INDEX_CONFIGS.put("company_desc", Index.ANALYZED);
		INDEX_CONFIGS.put("school_name", Index.ANALYZED);
		INDEX_CONFIGS.put("school_desc", Index.ANALYZED);
		INDEX_CONFIGS.put("retain_eligibility", Index.ANALYZED);
		INDEX_CONFIGS.put("english_desc", Index.ANALYZED);
		INDEX_CONFIGS.put("english_practice_content", Index.ANALYZED);
		INDEX_CONFIGS.put("desc", Index.ANALYZED);
		INDEX_CONFIGS.put("expertise", Index.ANALYZED);
	}
}
